package network

import (
	"bytes"
	_ "bytes"
	_ "encoding"
	"encoding/binary"
	_ "encoding/binary"
	"errors"
	_ "fmt"
	"log"
	"net"
	"sync"
	"tcptemplate/logger"
	"tcptemplate/util"
	"time"
	_ "time"

	"github.com/davecgh/go-spew/spew"
	_ "github.com/golang/protobuf/proto"
	"github.com/hprose/hprose-golang/io"
	"golang.org/x/net/context"
)

const (
	PKG_MAX_LENGTH = 1024
)

var (
	ERR_CHAN_CLOSE = errors.New("CHANEL CLOSED")
)

type PackHeader struct {
	Identify [2]byte
	Length   int32
	Verify   byte
}

type PackageHandler interface {
	Read() []byte
	Write([]byte)
}

type ProcessContext struct {
	context   context.Context
	receiever *PackageReceiever
	c         *net.Conn
	h         HandleFunction
}

//todo 如果需要接收方多携程，还需要实现一个mutex
type PackageReceiever struct {
	pack_data     []byte //正在组包的数据
	pack_len      int
	cache_package chan []byte
	reader        io.Reader
	mutex         sync.Mutex
	PackageHandler
}

func (this *PackageReceiever) Cleared() bool {
	// 没有正在缓存的数据包
	if len(this.cache_package) == 0 && this.pack_len == 0 {
		return true
	} else {
		return false
	}
}
func (this *PackageReceiever) PackageCleared() bool {
	if len(this.cache_package) == 0 {
		return true
	} else {
		return false
	}
}
func (this *PackageReceiever) Unsort() bool {
	if this.pack_len == 0 {
		return false
	} else {
		return true
	}
}

func (this *PackageReceiever) ReadNonBlock() ([]byte, error) {
	if len(this.cache_package) > 0 {
		ret, ok := <-this.cache_package
		if ok != true {
			return nil, ERR_CHAN_CLOSE
		}
		return ret[7:], nil
	} else {
		return nil, nil
	}
}

/*
type FrameHeader struct {
	Segment [4]byte
	Length int64
	Verify byte
}
*/
var (
	ErrPackFormat    = errors.New("Error Package format error")
	ErrorPackTooLong = errors.New("Package too long")
	ErrorPackVerify  = errors.New("Package verify fail")
)

func PackageReceieverFactory() *PackageReceiever {
	obj := new(PackageReceiever)
	obj.pack_data = make([]byte, util.MAX_PACKAGE_BUFFER)
	//最大缓存的包数据
	obj.cache_package = make(chan []byte, PKG_MAX_LENGTH)
	return obj
}

type UserError struct {
	Err string
}

func (this *UserError) Error() string {
	return this.Err
}

func (this *PackageReceiever) Write(input []byte, inputlen int) error {
	if inputlen == 0 {
		return nil
	}
	// 有缓存中的数据
	if this.pack_len > 0 {
		copy(this.pack_data[this.pack_len:], input[0:inputlen])
		this.pack_len += inputlen
		if this.pack_data[0] != 0x40 || this.pack_data[1] != 0x41 {
			return ErrPackFormat
		}
		// verify
		bpacklen := bytes.NewReader(this.pack_data[2:6])
		var packlen int32
		var verify byte
		e := binary.Read(bpacklen, binary.BigEndian, &packlen)
		if nil != e {
			logger.LogDebugError(e.Error())
		}
		for _, v := range this.pack_data[2:6] {
			verify += v
		}
		if verify != this.pack_data[6] {
			return ErrorPackVerify
		}
		// 还没完全收到一整包数据
		if packlen < int32(inputlen)-7 {
			return nil
		}
		// 刚好等于一包数据
		if packlen == int32(inputlen)-7 {
			_, ok := <-this.cache_package
			if !ok {
				logger.LogDebugError("channel is closed")
				return nil
			}
			this.cache_package <- this.pack_data[0:inputlen]
			this.pack_len = 0
		}
		// 有两个包
		if packlen < int32(inputlen)-7 {
			_, ok := <-this.cache_package
			if !ok {
				logger.LogDebugError("channel is closed")
				return nil
			}
			this.cache_package <- this.pack_data[0:inputlen]
			this.pack_len = 0
			this.Write(this.pack_data[inputlen:], this.pack_len-int(packlen)) //下个包再去重组包
		}
	}
	// 没有未完成的组包
	if this.pack_len == 0 {
		if input[0] != 0x40 || input[1] != 0x41 {
			return ErrPackFormat
		}
		// verify
		bpacklen := bytes.NewReader(input[2:6])
		var packlen int32
		var verify byte
		e := binary.Read(bpacklen, binary.BigEndian, &packlen)
		if nil != e {
			logger.LogDebugError(e.Error())
		}
		for _, v := range input[2:6] {
			verify += v
		}
		if verify != input[6] {
			return ErrorPackVerify
		}
		// 还没完全收到一整包数据
		if packlen < int32(inputlen)-7 {
			copy(this.pack_data[this.pack_len:], input[0:inputlen])
			this.pack_len += inputlen
			return nil
		}
		// 刚好等于一包数据
		if packlen == int32(inputlen)-7 {
			this.cache_package <- input[0:inputlen]
			this.pack_len = 0
		}
		// 有两个包
		if packlen < int32(inputlen)-7 {
			this.cache_package <- input[0:inputlen]
			this.pack_len = 0
			this.Write(input[inputlen:], inputlen-int(packlen)) //下个包再去重组包
		}
	}

	return nil
}

type HandleFunction func(ctx ProcessContext)

var gHandler HandleFunction = nil

func SetHandler(h HandleFunction) {
	gHandler = h
}

func DefaultPackageHandler(ctx ProcessContext) {
	pack, e := ctx.receiever.ReadNonBlock()
	if e != nil {
		logger.LogDebugError(e.Error())
		return
	}
	logger.LogRealeaseInfo((*ctx.c).RemoteAddr().String() + "[send]" + spew.Sprintf("%v", pack))
	_, e = (*ctx.c).Write(pack)
	if e != nil {
		logger.LogDebugError(e.Error())
	}
}

func CloseConnection(c ConnectionContext, receiver *PackageReceiever) {
	e := c.Cnn.Close()
	if nil != e {
		logger.LogDebugError(e.Error())
	}
	close(receiver.cache_package)
	logger.LogRealeaseInfo("close socket " + c.sockId)
	e = GetConnMgr().DeleteConn(c.sockId)
	if nil != e {
		logger.LogDebugError(e.Error())
	}
}

func HandleConnection(c ConnectionContext) {
	buf := make([]byte, PKG_MAX_LENGTH) // 这个1024可以根据你的消息长度来设置
	packReceiever := PackageReceieverFactory()
	pCtx := ProcessContext{c, packReceiever, &c.Cnn, c.h}

	for {
		for !packReceiever.PackageCleared() {
			//修改handler 机制
			if nil != gHandler {
				gHandler(pCtx)
			} else {
				c.h(pCtx)
			}
		}
		recvd := 0
		var err error
		recvd, err = c.Cnn.Read(buf)
		log.Print(recvd)
		for recvd < 7 {
			smallbuf := make([]byte, 100) // 这个1024可以根据你的消息长度来设置
			var n int
			c.Cnn.SetReadDeadline(time.Now().Add(time.Second))
			n, err = c.Cnn.Read(smallbuf)
			if err != nil {
				if nerr, ok := err.(net.Error); ok && !nerr.Temporary() {
					CloseConnection(c, packReceiever)
					return
				}
			}
			if n > 0 {
				logger.LogRealeaseInfo(smallbuf)
				copy(buf[recvd:], smallbuf[0:n])
				recvd += n
			}
		}
		logger.LogRealeaseInfo(buf)
		err = packReceiever.Write(buf, recvd)
		//注意，用了chanel不要在同一个携程里面进行插入和取出，以免造成死锁。
		if err != nil {
			log.Println(err.Error())
			//log.Println("conection drop down")
			e := c.Cnn.Close()
			if nil != e {
				logger.LogDebugError(e.Error())
			}
			t := <-packReceiever.cache_package
			if len(t) != 0 {
				close(packReceiever.cache_package)
			}
			e = GetConnMgr().DeleteConn(c.sockId)
			if nil != e {
				logger.LogDebugError(e.Error())
			}
			return
		}
		if len(c.Done()) > 0 {
			l := <-c.Done()
			if dead, ok := c.Deadline(); ok {
				if time.Now().Add(time.Nanosecond).After(dead) {
					logger.LogRealeaseInfo("connection timeout")
					// timeout
				}
			} else {
				logger.LogRealeaseInfo("connection cancled")
				//canceld
			}
			l = l
		}

	}
}
